﻿using AJWPFAdmin.Core;
using AJWPFAdmin.Core.Components.ViewModels;
using AJWPFAdmin.Core.Components.Views;
using AJWPFAdmin.Core.Enums;
using AJWPFAdmin.Core.ExtensionMethods;
using AJWPFAdmin.Core.HardwareSDKS.EQLED;
using AJWPFAdmin.Core.Models.EF.Tables;
using AJWPFAdmin.Core.Utils;
using AJWPFAdmin.Core.Validation;
using AJWPFAdmin.Services.EF;
using Masuit.Tools;
using Masuit.Tools.Core.Validator;
using Masuit.Tools.Systems;
using Microsoft.EntityFrameworkCore;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Yitter.IdGenerator;
using static AJWPFAdmin.Core.ExceptionTool;

namespace EntranceGuardManager.Modules.Main.ViewModels
{
    public class EQLEDFormViewModel : AnnotationValidationViewModel, IDialogAware
    {
        private string _dialogTitle;
        public string DialogTitle
        {
            get { return _dialogTitle; }
            set { SetProperty(ref _dialogTitle, value); }
        }

        private bool _loading;
        public bool Loading
        {
            get { return _loading; }
            set { SetProperty(ref _loading, value); }
        }

        private EQLEDControlConfigModel _form;

        private List<EQLEDControlConfigModel> _source;

        private bool _editMode;

        #region FormItems

        private int _lineHeight;
        /// <summary>
        /// 每一行高度
        /// </summary>
        [Display(Name = "行高")]
        [MinValue(0, ErrorMessage = "{0}至少为1且不能为负数")]
        public int LineHeight
        {
            get { return _lineHeight; }
            set { SetProperty(ref _lineHeight, value); }
        }

        private Dictionary<string, EQLEDCardType> _cardTypeOptions;
        public Dictionary<string, EQLEDCardType> CardTypeOptions
        {
            get => _cardTypeOptions;
            set => SetProperty(ref _cardTypeOptions, value);
        }

        private EQLEDCardType _cardType;
        /// <summary>
        /// 控制卡类型
        /// </summary>
        public EQLEDCardType CardType { get => _cardType; set => SetProperty(ref _cardType, value); }


        private Dictionary<string, EQLEDFontColor> _fontColorOptions;
        public Dictionary<string, EQLEDFontColor> FontColorOptions
        {
            get => _fontColorOptions;
            set => SetProperty(ref _fontColorOptions, value);
        }

        private int _cardAddress;
        /// <summary>
        /// 控制卡地址, 1 ~ 1024
        /// </summary>
        [Display(Name = "控制卡地址")]
        [Range(1, 1024, ErrorMessage = "{0}须在 {1} ~ {2} 之间")]
        public int CardAddress { get => _cardAddress; set => SetProperty(ref _cardAddress, value); }

        private Dictionary<string, EQLEDCommunicationMode> _eqLEDCommunicationModeOptions;
        public Dictionary<string, EQLEDCommunicationMode> CommunicationModeOptions
        {
            get => _eqLEDCommunicationModeOptions;
            set => SetProperty(ref _eqLEDCommunicationModeOptions, value);
        }

        private EQLEDCommunicationMode _eqLEDCommunicationMode;
        /// <summary>
        /// 通讯方式
        /// </summary>
        public EQLEDCommunicationMode CommunicationMode
        {
            get => _eqLEDCommunicationMode;
            set => SetProperty(ref _eqLEDCommunicationMode, value);
        }

        private Dictionary<string, int> _serialNumOptions;
        public Dictionary<string, int> SerialNumOptions
        {
            get => _serialNumOptions;
            set => SetProperty(ref _serialNumOptions, value);
        }

        private int _serialNum;
        /// <summary>
        /// 串口号
        /// </summary>
        public int SerialNum { get => _serialNum; set => SetProperty(ref _serialNum, value); }

        private List<int> _serialBaudOptions;
        public List<int> SerialBaudOptions
        {
            get => _serialBaudOptions;
            set => SetProperty(ref _serialBaudOptions, value);
        }
        private int _serialBaud;
        /// <summary>
        /// 波特率
        /// </summary>
        public int SerialBaud { get => _serialBaud; set => SetProperty(ref _serialBaud, value); }

        private int _netPort;
        /// <summary>
        /// 网络端口
        /// </summary>
        [Display(Name = "网络端口")]
        [Range(1, 65535, ErrorMessage = "{0} 须在 {1} ~ {2}之间")]
        public int NetPort { get => _netPort; set => SetProperty(ref _netPort, value); }

        private string _ipAddress;
        /// <summary>
        /// IP地址
        /// </summary>
        [Display(Name = "IP地址")]
        [AJFormIPField(ErrorMessage = "IP地址格式有误")]
        public string IpAddress { get => _ipAddress; set => SetProperty(ref _ipAddress, value); }

        private int _screenWidth;
        /// <summary>
        /// 屏幕宽度
        /// </summary>
        public int ScreenWidth { get => _screenWidth; set => SetProperty(ref _screenWidth, value); }

        private int _screenHeight;
        /// <summary>
        /// 屏幕高度
        /// </summary>
        public int ScreenHeight { get => _screenHeight; set => SetProperty(ref _screenHeight, value); }


        private Dictionary<string, EQLEDColorStyle> _colorStyleOptions;
        public Dictionary<string, EQLEDColorStyle> ColorStyleOptions
        {
            get => _colorStyleOptions;
            set => SetProperty(ref _colorStyleOptions, value);
        }

        private EQLEDColorStyle _colorStyle;
        /// <summary>
        /// 屏幕颜色
        /// </summary>
        public EQLEDColorStyle ColorStyle { get => _colorStyle; set => SetProperty(ref _colorStyle, value); }

        private ObservableCollection<PassagewayCheckWrapper> _passagewayOptions;
        public ObservableCollection<PassagewayCheckWrapper> PassagewayOptions
        {
            get => _passagewayOptions;
            set => SetProperty(ref _passagewayOptions, value);
        }

        private ObservableCollection<EQLEDLineItemConfig> _lineConfigs;
        public ObservableCollection<EQLEDLineItemConfig> LineConfigs
        {
            get => _lineConfigs;
            set => SetProperty(ref _lineConfigs, value);
        }

        #endregion

        private DelegateCommand<PassagewayCheckWrapper> _passagewayCheckCmd;
        public DelegateCommand<PassagewayCheckWrapper> PassagewayCheckCmd =>
            _passagewayCheckCmd ?? (_passagewayCheckCmd = new DelegateCommand<PassagewayCheckWrapper>(ExecutePassagewayCheckCmd));

        void ExecutePassagewayCheckCmd(PassagewayCheckWrapper parameter)
        {
            parameter.Checked = true;
        }

        private DelegateCommand<PassagewayCheckWrapper> _passagewayUnCheckCmd;
        public DelegateCommand<PassagewayCheckWrapper> PassagewayUnCheckCmd =>
            _passagewayUnCheckCmd ?? (_passagewayUnCheckCmd = new DelegateCommand<PassagewayCheckWrapper>(ExecutePassagewayUnCheckCmd));

        void ExecutePassagewayUnCheckCmd(PassagewayCheckWrapper parameter)
        {

            parameter.Checked = false;
        }

        private DelegateCommand _saveCmd;
        public DelegateCommand SaveCmd =>
            _saveCmd ?? (_saveCmd = new DelegateCommand(ExecuteSaveCmdAsync, CanExecuteSaveCmd));

        void ExecuteSaveCmdAsync()
        {
            if (!ValidateModel())
            {
                SaveCmd.RaiseCanExecuteChanged();

                AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                {
                    Title = "提示",
                    Message = $"表单校验失败,请检查所填数据",
                    Detail = string.Join(";", ValidationErrorsByProperty.SelectMany(p => p.Value).Select(p => p.ToString()))
                });
                return;
            }

            if (LineHeight > ScreenHeight)
            {
                ExceptionTool.FriendlyError("行高不能超过屏幕高度", dialogId: DialogIds.DialogWindow);
                return;
            }

            if (this.CommunicationMode == EQLEDCommunicationMode.网络)
            {
                if (string.IsNullOrWhiteSpace(this.IpAddress))
                {
                    ExceptionTool.FriendlyError("IP地址必须填写", dialogId: DialogIds.DialogWindow);
                    return;
                }
            }

            Loading = true;

            if (!_editMode)
            {
                if (this.CommunicationMode == EQLEDCommunicationMode.网络)
                {
                    if (string.IsNullOrWhiteSpace(this.IpAddress))
                    {
                        ExceptionTool.FriendlyError("IP地址必须填写", dialogId: DialogIds.DialogWindow);
                        return;
                    }

                    if (_source.Any(p => p.IpAddress == this.IpAddress))
                    {
                        ExceptionTool.FriendlyError("相同IP地址的LED已存在", dialogId: DialogIds.DialogWindow);
                        return;
                    }
                }
                else
                {
                    if (_source.Any(p => p.SerialNum == this.SerialNum))
                    {
                        ExceptionTool.FriendlyError("相同串口的LED已存在", dialogId: DialogIds.DialogWindow);
                        return;
                    }
                }
                _form.Id = YitIdHelper.NextId();
            }
            else
            {
                if (this.CommunicationMode == EQLEDCommunicationMode.网络)
                {
                    if (_form.IpAddress != this.IpAddress && _source.Any(p => p.IpAddress == this.IpAddress))
                    {
                        ExceptionTool.FriendlyError("相同IP地址的LED已存在", dialogId: DialogIds.DialogWindow);
                        return;
                    }
                }
                else
                {
                    if (_form.SerialNum != this.SerialNum && _source.Any(p => p.SerialNum == this.SerialNum))
                    {
                        ExceptionTool.FriendlyError("相同串口的LED已存在", dialogId: DialogIds.DialogWindow);
                        return;
                    }
                }

            }

            var checkedPassageways = PassagewayOptions.Where(p => p.Checked);
            if (!checkedPassageways.Any())
            {
                ExceptionTool.FriendlyError("未选择任何道闸", dialogId: DialogIds.DialogWindow);
                return;
            }

            _form.CardType = CardType;
            _form.CardAddress = CardAddress;
            _form.CommunicationMode = CommunicationMode;
            _form.SerialNum = SerialNum;
            _form.SerialBaud = SerialBaud;
            _form.NetPort = NetPort;
            _form.IpAddress = IpAddress;
            _form.ScreenWidth = ScreenWidth;
            _form.ScreenHeight = ScreenHeight;
            _form.ColorStyle = ColorStyle;
            _form.LineHeight = LineHeight;
            _form.PassagewayIds = checkedPassageways.Select(p => p.Data.Id).ToArray();
            _form.PassagewayNames = string.Join(",", checkedPassageways.Select(p => p.Data.Name));
            _form.LineConfigs = LineConfigs.OrderBy(p => p.LineNumber).ToList();

            Loading = false;

            RequestClose?.Invoke(new DialogResult(ButtonResult.OK, new DialogParameters
            {
                {"data", _form }
            }));
        }

        bool CanExecuteSaveCmd()
        {
            return !HasErrors;
        }

        public string Title => string.Empty;

        public event Action<IDialogResult> RequestClose;

        public bool CanCloseDialog()
        {
            return true;
        }

        public void OnDialogClosed()
        {

        }

        public async void OnDialogOpened(IDialogParameters parameters)
        {
            parameters.TryGetValue<EQLEDControlConfigModel>("data", out var data);
            parameters.TryGetValue("source", out _source);
            DialogTitle = data == null ? $"新增 EQ LED" : $"编辑 {data.CardType}";

            var passagewaySource = await _db.Passageways.OrderBy(p => p.Id).AsNoTracking().ToListAsync();

            PassagewayOptions = new ObservableCollection<PassagewayCheckWrapper>(passagewaySource.Select(p => new PassagewayCheckWrapper
            {
                Data = p
            }).ToList());

            _editMode = data != null;

            if (_editMode)
            {
                _form = data;
                CardType = data.CardType;
                CardAddress = data.CardAddress;
                CommunicationMode = data.CommunicationMode;
                SerialNum = data.SerialNum;
                SerialBaud = data.SerialBaud;
                NetPort = data.NetPort;
                IpAddress = data.IpAddress;
                ScreenWidth = data.ScreenWidth;
                ScreenHeight = data.ScreenHeight;
                ColorStyle = data.ColorStyle;
                LineHeight = data.LineHeight;

                InitLineConfigs(data.LineConfigs);

                foreach (var item in PassagewayOptions)
                {
                    item.Checked = data.PassagewayIds?.Count() > 0 && data.PassagewayIds.Contains(item.Data.Id);
                }
            }
            else
            {
                CardType = EQLEDCardType.EQ3002I;
                CardAddress = 1;
                CommunicationMode = EQLEDCommunicationMode.网络;
                SerialNum = 1;
                SerialBaud = 9600;
                NetPort = 5005;
                IpAddress = "127.0.0.1";
                ScreenWidth = 64;
                ScreenHeight = 32;
                ColorStyle = EQLEDColorStyle.单色屏;
                LineHeight = 16;
                InitLineConfigs(null);
            }

        }

        public void InitLineConfigs(List<EQLEDLineItemConfig> source)
        {
            if (source == null || source.Count == 0)
            {
                source = new List<EQLEDLineItemConfig>();
                for (int i = 0; i < 10; i++)
                {
                    source.Add(new EQLEDLineItemConfig
                    {
                        LineNumber = i + 1,
                        FontColor = i % 2 == 0 ? EQLEDFontColor.红色 : EQLEDFontColor.黄色,
                        FontSize = 12
                    });
                }
            }
            LineConfigs = new ObservableCollection<EQLEDLineItemConfig>(source);
        }

        private AJGlobalExceptionResolvedEvent _globalExceptionEvt;
        private DbService _db;

        public EQLEDFormViewModel(DbService db,
            IEventAggregator eventAggregator)
        {
            _db = db;
            _form = new EQLEDControlConfigModel
            {
                CardType = EQLEDCardType.EQ3002I,
                CardAddress = 1,
                CommunicationMode = EQLEDCommunicationMode.网络,
                SerialNum = 1,
                SerialBaud = 9600,
                NetPort = 5005,
                IpAddress = "127.0.0.1",
                ScreenWidth = 64,
                ScreenHeight = 32,
                ColorStyle = EQLEDColorStyle.单色屏,
            };
            _globalExceptionEvt = eventAggregator.GetEvent<AJGlobalExceptionResolvedEvent>();
            _globalExceptionEvt.Subscribe(() =>
            {
                Loading = false;
            });

            CardTypeOptions = CommonUtil.EnumToDictionary<EQLEDCardType>(null);
            FontColorOptions = CommonUtil.EnumToDictionary<EQLEDFontColor>(null);
            CommunicationModeOptions = CommonUtil.EnumToDictionary<EQLEDCommunicationMode>(null);

            var portOptions = new Dictionary<string, int>();
            for (int i = 1; i <= 17; i++)
            {
                portOptions.Add($"COM{i}", i);
            }
            SerialNumOptions = portOptions;
            SerialBaudOptions = new List<int>
            {
                9600,19200,57600,115200
            };
            ColorStyleOptions = CommonUtil.EnumToDictionary<EQLEDColorStyle>(null);
        }
    }

    public class PassagewayCheckWrapper : BindableBase
    {
        private bool _checked;
        public bool Checked
        {
            get { return _checked; }
            set { SetProperty(ref _checked, value); }
        }

        public Passageway Data { get; set; }
    }
    public class CommunicationModeToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is EQLEDCommunicationMode model && parameter is string tag)
            {
                return model == Enum.Parse<EQLEDCommunicationMode>(tag) ? Visibility.Visible : Visibility.Collapsed;
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
}
